package com.mfp.java.testYou.db.mock;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

import com.mfp.java.testYou.core.AppContext;
import com.mfp.java.testYou.db.DataAccessObject;
import com.mfp.java.testYou.db.UnauthorizedException;
import com.mfp.java.testYou.db.model.CompletedTest;
import com.mfp.java.testYou.db.model.Question;
import com.mfp.java.testYou.db.model.Test;
import com.mfp.java.testYou.db.model.User;

/**
 * Creates a mock data for testing purposes. Usage not reccommended. Is very
 * slow.
 */
public class MockDAO implements DataAccessObject {

	private static Logger log = Logger.getLogger(MockDAO.class);

	private static final String MOCK_DB_LOC = "mock.db";

	private MockPersisterObject mpo;

	private static synchronized void persist(MockPersisterObject o) {
		log.info("Starting persist");

		String path = AppContext.getBasePath();

		try {
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(path, MOCK_DB_LOC)));
			oos.writeObject(o);
			oos.flush();
			oos.close();
			log.info("Persisted");
		} catch (FileNotFoundException e) {
			log.error("Could not save file: " + e.getClass().getName() + " " + e.getMessage());
		} catch (IOException e) {
			log.error("Could not save file: " + e.getClass().getName() + " " + e.getMessage());
		}
	}

	public MockDAO() {
		String path = AppContext.getBasePath();
		try {
			FileInputStream fis = new FileInputStream(new File(path, MOCK_DB_LOC));
			ObjectInputStream ois = new ObjectInputStream(fis);
			Object o = ois.readObject();
			mpo = (MockPersisterObject) o;
		} catch (FileNotFoundException e) {
			log.info("Mock db file not found");
		} catch (IOException e) {
			log.warn("Problem with mock db file: " + e.getClass().getName() + " " + e.getMessage());
		} catch (ClassNotFoundException e) {
			log.warn("Problem with mock db file: " + e.getClass().getName() + " " + e.getMessage());
		} catch (ClassCastException e) {
			log.warn("Problem with mock db file: " + e.getClass().getName() + " " + e.getMessage());
		}

		if (mpo == null) {
			mpo = new MockPersisterObject();
		}
	}

	@Override
	public List<User> getAllUsers() {
		return mpo.getAllUsers();
	}

	@Override
	public User getUser(String username, CharSequence password) throws UnauthorizedException {
		for (User us : mpo.getAllUsers()) {
			UserWithPass uwp = ((UserWithPass) us);
			if (uwp.getUserName().equals(username) && uwp.getPass().equals(password)) {
				return uwp;
			}
		}
		throw new UnauthorizedException("User with pass not found");
	}

	@Override
	public User getUser(Integer userId) {
		for (User u : mpo.getAllUsers()) {
			if (u.getId() == userId) {
				return u;
			}
		}
		throw new IllegalArgumentException("No user found with ID: " + userId);
	}

	@Override
	public User addUser(User user, CharSequence pass) {
		User savedUser = mpo.addUser(user, pass);
		persist(mpo);
		return savedUser;
	}

	@Override
	public void deleteUser(Integer userId) throws SQLException {
		mpo.deleteUser(userId);
		persist(mpo);
	}

	@Override
	public User editUser(User newUserData, CharSequence pass, int userId) throws SQLException, IllegalArgumentException {
		User newUser = mpo.editUser(newUserData, pass, userId);
		persist(mpo);
		return newUser;
	}

	public List<Question> getAllQuestions() {
		return mpo.getAllQuestions();
	}

	public Question getQuestion(Integer id) {
		for (Question q : getAllQuestions()) {
			if (q.getId() == id) {
				return q;
			}
		}
		throw new IllegalArgumentException("No question found with ID: " + id);
	}

	@Override
	public Question addQuestion(Question q) {
		Question q2 = mpo.addQuestion(q);
		persist(mpo);
		return q2;
	}

	@Override
	public void deleteQuestion(Integer questionId) throws SQLException, IllegalArgumentException {
		mpo.deleteQuestion(questionId);
		persist(mpo);
	}

	@Override
	public Question editQuestion(Question question, Integer qIdInt) throws SQLException, IllegalArgumentException {
		Question newQuestion = mpo.editQuestion(question, qIdInt);
		persist(mpo);
		return newQuestion;
	}

	@Override
	public List<Test> getAllTests() {
		return mpo.getAllTests();
	}

	@Override
	public Test addTest(Test t) throws SQLException, IllegalArgumentException {
		Test t2 = mpo.addTest(t);
		persist(mpo);
		return t2;
	}

	@Override
	public Test getTest(Integer testIdInt) {
		for (Test t : mpo.getAllTests()) {
			if (t.getId() == testIdInt) {
				return t;
			}
		}
		throw new IllegalArgumentException("No test found with ID: " + testIdInt);
	}

	@Override
	public void deleteTest(Integer testIdInt) throws SQLException, IllegalArgumentException {
		mpo.deleteTest(testIdInt);
		persist(mpo);
	}

	@Override
	public Test editTest(Test test, Integer testIdInt) throws SQLException, IllegalArgumentException {
		Test newTest = mpo.editTestDetails(test, testIdInt);
		persist(mpo);
		return newTest;
	}

	@Override
	public void addQuestionToTest(Integer testId, Integer questionId) throws SQLException, IllegalArgumentException {
		mpo.addQuestionToTest(testId, questionId);
		persist(mpo);
	}

	@Override
	public void deleteQuestionFromTest(Integer testId, Integer questionId) throws SQLException, IllegalArgumentException {
		mpo.deleteQuestionFromTest(testId, questionId);
		persist(mpo);

	}

	@Override
	public List<Test> getFinalTests() {
		List<Test> list = new LinkedList<Test>();
		for (Test t : AppContext.getDAO().getAllTests()) {
			if (t.isFinalTest()) {
				list.add(t);
			}
		}
		return list;
	}

	@Override
	public void addCompletedTest(CompletedTest ct) throws SQLException {
		log.debug("Adding: " + ct);
		mpo.addCompletedTest(ct);
		persist(mpo);
	}

	@Override
	public List<CompletedTest> getAllCompletedTests() {
		return mpo.getAllResults();
	}

}
